function Xiangqi(group){
    this.group = group===0 ? 0 : 1;
    //是否为当前落子
    this.isCurrent = false;
}
function report1(i, j){
    var x1,y1,action,
        number = ["一","二","三","四","五","六","七","八","九"];
    var offsety = j - this.location.y;
    var offsetx = i - this.location.x;
    x1 = this.group == 1 ? this.location.x : 8-this.location.x;
    if(offsety != 0){
        if(offsety > 0){
            action = this.group == 0 ? "退" : "进";
            y1 = offsety -1;
        }else{
            action = this.group == 0 ? "进" : "退";
            y1 = -offsety - 1;
        }
    }else{
        y1 = this.group == 1 ? i : 8-i;
        action = "平";
    }
    info(this.text + (this.group==0 ? number[x1] : x1+1) + action + (this.group==0 ? number[y1] : y1+1));
}
function report2(i, j){
    var x1,y1,action,
        number = ["一","二","三","四","五","六","七","八","九"];
    var offsety = j - this.location.y;
    x1 = this.group == 1 ? this.location.x : 8-this.location.x;
    if(offsety > 0){
        action = this.group == 0 ? "退" : "进";
    }else{
        action = this.group == 0 ? "进" : "退";
    }
    y1 = this.group == 1 ? i : 8-i;
    info(this.text + (this.group==0 ? number[x1] : x1+1) + action + (this.group==0 ? number[y1] : y1+1));
}
/**
 * 根据坐标落子
 * @param coordinate
 */
Xiangqi.prototype.init = function(ctx, location, board){
    ctx.beginPath();
    ctx.save();
    ctx.fillStyle = !this.isCurrent ? "#CC9966" : "#00FF33";
    var point = {
        x: board.array[location.x][location.y].point.x,
        y: board.array[location.x][location.y].point.y
    }
    ctx.arc(point.x, point.y, board.space*0.35, 0, Math.PI*2, true);
    ctx.fill();
    ctx.font = board.space*0.6 + "px 宋体";
    ctx.fillStyle = "rgb(" + (this.group==0 ? 255 : 0) + ",0,0)";
    ctx.textBaseline = "top";
    ctx.fillText(this.text, point.x-board.space*0.3, point.y-board.space*0.3);
    this.location = {x: location.x, y: location.y};
    ctx.restore();

}
Xiangqi.prototype.canMove = function(board, location){
    if(!this.canEat(board, location))
        return false;
    return true;
};
Xiangqi.prototype.canEat = function(board, location){
    var target = board.array[location.x][location.y].xiangqi;
    //同一阵营不能吃
    if(target != 0 && this.group == target.group)
        return false;
    return true;
}
Xiangqi.prototype.report = report1;
var Rook = function(group){
    Xiangqi.apply(this, arguments);
    this.text = "車";
}
Rook.prototype = new Xiangqi();
Rook.prototype.canMove = function(board, location){
    if(!this.canEat(board, location))
        return false;
    var offsety = this.location.y - location.y;
    var offsetx = this.location.x - location.x;
    var array = board.array;
    //只走直线
    if(offsety != 0 && offsetx != 0)
        return false;
    //中间没棋子
    var i, min, max;
    if(offsetx == 0){
        if(offsety > 0){
            min = location.y;
            max = this.location.y;
        }else{
            max = location.y;
            min = this.location.y;
        }
    }else{
        if(offsetx > 0){
            min = location.x;
            max = this.location.x;
        }else{
            max = location.x;
            min = this.location.x;
        }
    }
    for(i=min+1; i<max; i++){
        if((offsetx != 0 && array[i][location.y].xiangqi != 0) || (offsety != 0 && array[location.x][i].xiangqi != 0))
            return false;
    }
    return true;
};

var Knight = function(group){
    Xiangqi.apply(this, arguments);
    this.text = "馬";
}
Knight.prototype = new Xiangqi();
Knight.prototype.canMove = function(board, location){
    if(!this.canEat(board, location))
        return false;
    var offsetx = this.location.x - location.x;
    var offsety = this.location.y - location.y;
    //判断马步
    if(Math.abs(offsetx) == 2 && Math.abs(offsety) == 1){
        //别马腿
        return board.array[offsetx > 0 ? this.location.x - 1 : this.location.x + 1][this.location.y].xiangqi == 0;

    }else if(Math.abs(offsetx) == 1 && Math.abs(offsety) == 2){
        //别马腿
        return board.array[this.location.x][offsety > 0 ? this.location.y - 1 : this.location.y + 1].xiangqi == 0;
    }
    return false;
}
Knight.prototype.report = report2;

var Elephant = function(group){
    Xiangqi.apply(this, arguments);
    this.text = this.group===0 ? "相" : "象";
}
Elephant.prototype = new Xiangqi();
Elephant.prototype.canMove = function(board, location){
    if(!this.canEat(board, location))
        return false;
    var array = board.array;
    //枚举可以走的位置
    if(Math.abs(this.location.x - location.x)==2 && Math.abs(this.location.y - location.y)==2){
        //没有挡路的棋子
        if(array[(this.location.x + location.x) / 2][(this.location.y + location.y) / 2].xiangqi !== 0)
            return false;
        //不能越界
        if((this.group===0 && location.y>=5) || (this.group===1 && location.y<5)){
            return true;
        }else{
            return false;
        }
        return true;
    }
    return false;
}
Elephant.prototype.report = report2;

var Mandarin = function(group){
    Xiangqi.apply(this, arguments);
    this.text = this.group === 0 ? "仕" : "士";
}
Mandarin.prototype = new Xiangqi();
Mandarin.prototype.canMove = function(board, location){
    if(!this.canEat(board, location))
        return false;
    if(Math.abs(this.location.x - location.x)!=1 || Math.abs(this.location.y - location.y)!=1)
        return false;
    //是否出宫
    if(location.x < 3 || location.x > 5)
        return false;
    if((this.group == 0 && location.y < 7) || (this.group == 1 && location.y > 2))
        return false;
    return true;
}
Mandarin.prototype.report = report2;

var King = function(group){
    Xiangqi.apply(this, arguments);
    this.text = this.group===0 ? "帥" : "將";
}
King.prototype = new Xiangqi();
King.prototype.canMove = function(board, location){
    if(!this.canEat(board, location))
        return false;
    var array = board.array;
    var offsety = this.location.y - location.y;
    var offsetx = this.location.x - location.x;
    //两将中间无落子
    if(array[location.x][location.y].xiangqi !== 0
        && array[location.x][location.y].xiangqi instanceof King
        && this.location.x == location.x){
        for(var i=Math.min(this.location.y, location.y)+1; i<Math.max(this.location.y, location.y); i++){
            if(array[this.location.x][i].xiangqi !== 0)
                return false;
        }
        return true;
    }

        //是否出宫
    if(location.x < 3 || location.x > 5)
        return false;
    if((this.group == 0 && location.y < 7) || (this.group == 1 && location.y > 2))
        return false; //是否只一步
    if((Math.abs(offsetx) == 1 && offsety == 0) || (Math.abs(offsety) == 1 && offsetx == 0)){
        return true;
    }
    return false;
}

var Cannon = function(group){
    Xiangqi.apply(this, arguments);
    this.text = this.group === 0 ? "炮" : "砲";
}
Cannon.prototype = new Xiangqi();
Cannon.prototype.canMove = function(board, location){
    if(!this.canEat(board, location))
        return false;
    //走直线
    var offsety = this.location.y - location.y;
    var offsetx = this.location.x - location.x;
    var array = board.array;
    if(offsety != 0 && offsetx != 0)
        return false;
		
	var i, min, max, o=0;
	if(offsetx == 0){
		if(offsety > 0){
			min = location.y;
			max = this.location.y;
		}else{
			max = location.y;
			min = this.location.y;
		}
	}else{
		if(offsetx > 0){
			min = location.x;
			max = this.location.x;
		}else{
			max = location.x;
			min = this.location.x;
		}
	}
	for(i=min+1; i<max; i++){
		if((offsetx != 0 && array[i][location.y].xiangqi != 0) || (offsety != 0 && array[location.x][i].xiangqi != 0)){
			o++;
			if(o > 1)
				return false;
		}
	}
	//如果目标有棋子 则中间必须有一子
    if(o == 1 && array[location.x][location.y].xiangqi != 0)
       return true;
    //中间没棋子
	if(o == 0 && array[location.x][location.y].xiangqi == 0)
		return true;
    return false;
}

var Pawn = function(group){
    Xiangqi.apply(this, arguments);
    this.text = this.group===0 ? "兵" : "卒";
}
Pawn.prototype = new Xiangqi();
Pawn.prototype.canMove = function(board, location){
    if(!this.canEat(board, location))
        return false;
    //是否已过河
    var offsety = this.location.y - location.y;
    var offsetx = this.location.x - location.x;
    if(Math.abs(offsetx) == 1 && offsety == 0){
        //左右移动是否过河
        if((this.group===0 && location.y < 5 ) || (this.group ===1 && location.y >=5 ))
            return true;
    }
    if(Math.abs(offsety) == 1 && offsetx == 0){
        //只进不退
        if((this.group===0 && offsety > 0 ) || (this.group ===1 && offsety < 0))
            return true;
    }
    return false;
}
/**
 * 棋盘
 * @param ctx canvas context
 * @param cfg Object
 * {
 *      width: 棋盘宽度(必须)
 *      height: 棋盘高度(必须)
 *      margin: 外边距(可选)
 * }
 * @constructor
 */
function Board(ctx, cfg){
    this.width = cfg.width;
    this.height = cfg.height;
    this.margin = cfg.margin ? cfg.margin : 0;
    this.space = (this.width-2*this.margin)/8;
    this.array = [[],[],[],[],[],[],[],[],[],[]];
    this.step = 0;
    this.steps = [];
    this.init(ctx)
}
Board.prototype.init = function(ctx){
    var ctx = canvas.getContext("2d");
    var i, j, x;
    //象棋位置数组
    var xiangqi = [
        [Rook, Knight, Elephant, Mandarin, King],
        [0, 0, 0, 0, 0],
        [0, Cannon, 0, 0, 0],
        [Pawn, 0, Pawn, 0, Pawn],
        [0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0],
        [Pawn, 0, Pawn, 0, Pawn],
        [0, Cannon, 0, 0, 0],
        [0, 0, 0, 0, 0],
        [Rook, Knight, Elephant, Mandarin, King]
    ];
    for(i=0; i<9; i++){
        x = i>4 ? (i-(i-4)*2) : i;
        for(j=0; j<10; j++){
            this.array[i][j] = {};
            this.array[i][j].point = {
                x:this.margin+this.space*i,
                y:this.margin+this.space*j
            };
            this.array[i][j].xiangqi =  xiangqi[j][x] != 0 ? new xiangqi[j][x](j > 4 ? 0 : 1) : 0;
        }
    }
    //画棋盘
    this.draw(ctx);
    //落子
    this.locate(ctx);
    //事件
    this.initEvents(canvas);
    this.current = false;
}
Board.prototype.draw = function(ctx){
    var i;
    ctx.beginPath();
    ctx.strokeStyle = "rgb(0, 0, 0)";
    //frame
    ctx.moveTo(0, 0);
    ctx.lineTo(this.width, 0);
    ctx.lineTo(this.width, this.height);
    ctx.lineTo(0, this.height);
    ctx.lineTo(0, 0);
    ctx.stroke();
    //horizontal lines
    for(i=0; i<10; i++){
        ctx.moveTo(this.margin, (i*this.space)+this.margin);
        ctx.lineTo(this.margin+this.space*8, (i*this.space)+this.margin);
    }
    //vertical lines
    for(i=0; i<9; i++){
        ctx.moveTo((i*this.space)+this.margin, this.margin);
        ctx.lineTo((i*this.space)+this.margin, this.margin+this.space*4);
        ctx.moveTo((i*this.space)+this.margin, this.margin+this.space*5);
        ctx.lineTo((i*this.space)+this.margin, this.margin+this.space*9);
    }
    ctx.stroke();

    //the path of mandarins
    ctx.moveTo(this.margin+3*this.space, this.margin);
    ctx.lineTo(this.margin+5*this.space, this.margin+2*this.space);
    ctx.moveTo(this.margin+3*this.space, this.margin+7*this.space);
    ctx.lineTo(this.margin+5*this.space, this.margin+9*this.space);
    ctx.moveTo(this.margin+5*this.space, this.margin);
    ctx.lineTo(this.margin+3*this.space, this.margin+2*this.space);
    ctx.moveTo(this.margin+5*this.space, this.margin+7*this.space);
    ctx.lineTo(this.margin+3*this.space, this.margin+9*this.space);
    ctx.stroke();
    var drawMark = function(x, y, left, right){
        if(right){
            //bottom right
            ctx.moveTo(x+this.space/9+this.space/3, y+this.space/9);
            ctx.lineTo(x+this.space/9, y+this.space/9);
            ctx.lineTo(x+this.space/9, y+this.space/9+this.space/3);
            //top right
            ctx.moveTo(x+this.space/9+this.space/3, y-this.space/9);
            ctx.lineTo(x+this.space/9, y-this.space/9);
            ctx.lineTo(x+this.space/9, y-this.space/9-this.space/3);
        }
        if(left){
            //top left
            ctx.moveTo(x-this.space/9-this.space/3, y-this.space/9);
            ctx.lineTo(x-this.space/9, y-this.space/9);
            ctx.lineTo(x-this.space/9, y-this.space/9-this.space/3);
            //bottom left
            ctx.moveTo(x-this.space/9-this.space/3, y+this.space/9);
            ctx.lineTo(x-this.space/9, y+this.space/9);
            ctx.lineTo(x-this.space/9, y+this.space/9+this.space/3);
        }
    }
    //paws mark
    for(i=0; i<10; i++){
        var y = this.margin + 3*(i%2)*this.space + 3*this.space;
        var x = this.margin + Math.floor(i/2)*2*this.space;
        drawMark(x, y, i>1, i<8);
    }
    //cannons mark
    for(i=0; i<2; i++){
        var x = this.margin + this.space  +(i%2)*6*this.space;
        var y = this.margin + 2*this.space;
        drawMark(x, y, true, true);
        y = this.margin + 7*this.space;
        drawMark(x, y, true, true);
    }
    ctx.stroke();
    ctx.save();
    //楚河 汉界
    ctx.font = this.space*0.9+"px 宋体";
    ctx.fillStyle = "#000";
    var wordspace = (8*this.space - this.space*0.9*4)/5;
    ctx.fillText("楚", this.margin+wordspace, this.margin+this.space*5-0.2*this.space);
    ctx.fillText("河", this.margin+2*wordspace+this.space*0.9, this.margin+this.space*5-0.2*this.space);
    ctx.rotate(Math.PI);
    ctx.fillText("界", -this.margin-3*wordspace-3*+this.space*0.9, -this.margin-this.space*4-0.2*this.space);
    ctx.fillText("汉", -this.margin-4*wordspace-4*+this.space*0.9, -this.margin-this.space*4-0.2*this.space);
    ctx.restore();
    ctx.closePath();
}
//落子
Board.prototype.locate = function(ctx){
    var i, j;
    for(i=0; i<9; i++){
        for(j=0; j<10; j++){
            if(this.array[i][j].xiangqi !== 0)
                this.array[i][j].xiangqi.init(ctx, {x:i, y:j}, this);
                this.array[i][j].xiangqi.isCurrent = false;
        }
    }
}
Board.prototype.initEvents = function(canvas){
    var that = this;
    var ctx = canvas.getContext("2d");
    canvas.onmousedown = function(e){
        var i, j, x, y, onArc = false, msg;
        e = e||event;
        x = e.clientX - canvas.offsetLeft;
        y = e.clientY - canvas.offsetTop;

        for(i=0; i<9; i++){
            for(j=0; j<10; j++){
                //判断是否为可落子的区域
               if( isOnArc(that.array[i][j].point.x, that.array[i][j].point.y, that.space*0.3, x, y)){
                   //已经选中了一枚棋子
                   if(that.current){
                       //是否重复点击
                       if(i!=that.current.i || j!=that.current.j){
                            if(that.array[that.current.i][that.current.j].xiangqi.canMove(that, {x:i, y:j})){
                                if(that.step%2 != that.array[that.current.i][that.current.j].xiangqi.group){
                                    warn("轮到"+(that.step%2==0 ? "红" : "黑")+"方走!");
                                }else{
                                    //记录
                                    that.trace(i, j);
                                    //是否结束
                                    if(that.array[i][j].xiangqi instanceof  King){
                                        warn("恭喜"+(that.array[i][j].xiangqi.group == 0 ? "黑" : "红")+"方胜!");
                                    }
                                    that.array[i][j].xiangqi = that.array[that.current.i][that.current.j].xiangqi;
                                    that.array[that.current.i][that.current.j].xiangqi = 0;
                                }
                                that.current = false;
                                //如果不能移动，而且点到了其他棋子上则切换当前棋子
                            }else if(that.array[i][j].xiangqi !== 0){
                                that.array[i][j].xiangqi.isCurrent = true;
                                that.current = {i:i, j:j};
                            }else{
                                //点空
                                that.current = false;
                            }
                       }else{
                           that.current = false;
                       }
                   }else{
                       if(that.array[i][j].xiangqi !== 0){
                            that.array[i][j].xiangqi.isCurrent = true;
                            that.current = {i:i, j:j};
                       }
                   }
                   onArc = true;
                   break;
               }//if onarc
            }//for j
            if(this.current)
                break;
        }
        if(!onArc)
            that.current = false;
        ctx.clearRect(0, 0, this.width, this.height);
        that.draw(ctx);
        that.locate(ctx);
    }
}
Board.prototype.trace = function(i, j){
    this.steps.push({
            current:{
                location:{i: this.current.i, j:this.current.j},
                xiangqi: this.array[this.current.i][this.current.j].xiangqi
            },
            target:{
                location:{i: i, j:j},
                xiangqi: this.array[i][j].xiangqi
            }
        }
    );
    this.step++;
    this.array[this.current.i][this.current.j].xiangqi.report(i, j);
}
Board.prototype.undo = function(canvas){
    var ctx = canvas.getContext("2d");
    if(this.steps.length == 0)
        return false;
    var prestep = this.steps.pop();
    var current = prestep.current;
    var target = prestep.target;

    this.array[current.location.i][current.location.j].xiangqi = current.xiangqi;
    this.array[current.location.i][current.location.j].xiangqi.isCurrent  = true;
    this.array[target.location.i][target.location.j].xiangqi = target.xiangqi;
    this.step --;
    this.current = {i:current.location.i, j:current.location.j}
    ctx.clearRect(0, 0, this.width, this.height);
    this.draw(ctx);
    this.locate(ctx);
    return true;
}
function isOnArc(x, y, radius, x1, y1){
   return radius >= Math.sqrt(Math.pow(x1-x, 2) + Math.pow(y1-y, 2));
}